/*
** listbox.c
**
** Pictor, Version 1.51, Copyright (c) 1992-94 SoftCircuits
** Redistributed by permission.
*/

#include <stdio.h>
#include <ctype.h>
#include "pictor.h"

#define UPDATE_NOUPDATE 0
#define UPDATE_CURSOR   1
#define UPDATE_WINDOW   2

int _PL_lbcolwidth = 12;
int _PL_lbrows = 8;
int _PL_lbcols = 4;


/*
** Allows the user to select from a list of items using the cursor
** keys. TRUE is returned and *selection is set to the index of the
** selected item if the user pressed Enter. FALSE is returned and
** *selection is unchanged if Escape is pressed or numitems == 0.
**
** This function could be called recursively if it is active and
** help is selected.
*/
int listbox(char **items,int numitems,int *selection,
	char *title,COLORSTRUCT *colors)
{
	int done = FALSE,update = UPDATE_WINDOW,leftcol = 0;
	int i,j,key,top,left,row,col,newsel,oldsel = 0;

	newsel = *selection;

	if(numitems == 0)
		return(FALSE);

	top = center(_PL_lbrows + 2,_PL_rows);
	left = center((_PL_lbcols * (_PL_lbcolwidth + 2)) + 2,_PL_columns);

	wopen(top,left,_PL_lbrows + 2,(_PL_lbcols * (_PL_lbcolwidth + 2)) + 2,
		colors->normal,WO_STATICMEM | WO_SHADOW);
	wtitle(title);

	while(!done) {

		if(update != UPDATE_NOUPDATE) {

			if((newsel / _PL_lbrows) < leftcol) {
				leftcol = (newsel / _PL_lbrows);
				update = UPDATE_WINDOW;
			}
			else if((newsel / _PL_lbrows) >= (leftcol + _PL_lbcols)) {
				leftcol = (newsel / _PL_lbrows) - (_PL_lbcols - 1);
				update = UPDATE_WINDOW;
			}

			if(update == UPDATE_WINDOW) {

				vcolor(colors->normal);
				i = (leftcol * _PL_lbrows);

				for(col = 0;col < _PL_lbcols;col++) {
					for(row = 0;row < _PL_lbrows;row++,i++) {
						setwpos(row + 1,(col * (_PL_lbcolwidth + 2)) + 1);
						if(i < numitems) {
							wputc(' ');
							for(j = 0;j < _PL_lbcolwidth && items[i][j];j++) {
								wputc(items[i][j]);
							}
							wrepc(' ',(_PL_lbcolwidth + 1) - j);
						}
						else {
							wrepc(' ',_PL_lbcolwidth + 2);
						}
					}
				}
			}
			else {
				/* unhilight old selection */
				i = ((oldsel / _PL_lbrows) - leftcol);
				setwpos((oldsel % _PL_lbrows) + 1,(i * (_PL_lbcolwidth + 2)) + 1);
				wrepa(colors->normal,_PL_lbcolwidth + 2);
			}

			/* hilight new selection */
			i = ((newsel / _PL_lbrows) - leftcol);
			setwpos((newsel % _PL_lbrows) + 1,(i * (_PL_lbcolwidth + 2)) + 1);
			wrepa(colors->select,_PL_lbcolwidth + 2);

			update = UPDATE_NOUPDATE;
			oldsel = newsel;
		}
		switch(key = kbdread()) {
			case ENTER_KEY:
				*selection = newsel;
				done = TRUE;
				break;
			case ESCAPE_KEY:
				done = TRUE;
				break;
			case UP_KEY:
				if(newsel > 0) {
					newsel--;
					update = UPDATE_CURSOR;
				}
				else beep();
				break;
			case DOWN_KEY:
			case SPACE_BAR:
				if(newsel < (numitems - 1)) {
					newsel++;
					update = UPDATE_CURSOR;
				}
				else beep();
				break;
			case LEFT_KEY:
				if(newsel > 0) {
					if(newsel > _PL_lbrows) {
						newsel -= _PL_lbrows;
					}
					else {
						newsel = 0;
					}
					update = UPDATE_CURSOR;
				}
				else beep();
				break;
			case RIGHT_KEY:
				if(newsel < (numitems - 1)) {
					if(newsel < (numitems - _PL_lbrows)) {
						newsel += _PL_lbrows;
					}
					else {
						newsel = (numitems - 1);
					}
					update = UPDATE_CURSOR;
				}
				else beep();
				break;
			case PGUP_KEY:
				if(newsel > 0) {
					if(newsel > (_PL_lbrows * _PL_lbcols)) {
						newsel -= (_PL_lbrows * _PL_lbcols);
						if(leftcol > _PL_lbcols)
							leftcol -= _PL_lbcols;
						else
							leftcol = 0;
						update = UPDATE_WINDOW;
					}
					else {
						newsel = 0;
						update = UPDATE_CURSOR;
					}
				}
				else beep();
				break;
			case PGDN_KEY:
				if(newsel < (numitems - 1)) {
					if(newsel < (numitems - (_PL_lbrows * _PL_lbcols))) {
						newsel += (_PL_lbrows * _PL_lbcols);
						leftcol += _PL_lbcols;
						update = UPDATE_WINDOW;
					}
					else {
						newsel = (numitems - 1);
						update = UPDATE_CURSOR;
					}
				}
				else beep();
				break;
			case HOME_KEY:
				if(newsel > 0) {
					newsel = 0;
					update = UPDATE_CURSOR;
				}
				break;
			case END_KEY:
				if(newsel < (numitems - 1)) {
					newsel = (numitems - 1);
					update = UPDATE_CURSOR;
				}
				break;
			case F1_KEY:
				if(_PL_helpfunc != NULL)
					_PL_helpfunc(_PL_helpcontext);
				else beep();
				break;
			default:
				/* jump to selection if first letter pressed */
				kbdflush();
				key = toupper(key & 0xFF);
				if(isalnum(key)) {
					for(i = newsel + 1;i < numitems && !update;i++) {
						if(key == toupper(*items[i])) {
							newsel = i;
							update = UPDATE_CURSOR;
						}
					}
					for(i = 0;i <= newsel && !update;i++) {
						if(key == toupper(*items[i])) {
							newsel = i;
							update = UPDATE_CURSOR;
						}
					}
				}
				if(!update)
					beep();
				break;
		}
	}
	wclose();

	/* return TRUE if enter pressed */
	return(key == ENTER_KEY);

} /* listbox */
